package rad.framework.conv;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.persistence.EntityManager;

import rad.framework.jpa.HibernateUtil;
import rad.framework.jpa.TransactionScript;
import rad.framework.xml.BetwixtUtil;
import rad.framework.xml.BetwixtUtil.EmptySuppressionStrategy;

import org.apache.commons.betwixt.io.BeanWriter;
import org.hibernate.CacheMode;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;

public class ExportCommand extends BaseCommand {

	protected boolean oneFile = false;
	protected String eql = "";
	protected String suppressions = "";
	protected int batchSize = 20; // TODO constructor

	public ExportCommand(String eql, String persistenceUnitJndiName,
			String entityName, boolean oneFile, String suppressions) {
		super(persistenceUnitJndiName, entityName);
		this.eql = eql;
		this.oneFile = oneFile;
		this.suppressions = suppressions;
	}

	public void execute() throws Exception {
		new TransactionScript(persistenceUnitJndiName) {
			@Override
			protected Object run(EntityManager em) {
				if (oneFile) {
					singleFile(em);
				} else {
					multipleFiles(em);
				}
				return null;
			}
		}.run();
	}

	protected void singleFile(EntityManager em) {
		try {
			OutputStream fos = new FileOutputStream(getFileName());//new NoopOutputStream();//System.err;
			fos.write("<?xml version='1.0' ?><ArrayList>".getBytes());
			BeanWriter writer = BetwixtUtil.getBeanWriter(fos,
					new EmptySuppressionStrategy(suppressions));

			Session session = HibernateUtil.getSession(em);
			ScrollableResults results = session.createQuery(eql).setReadOnly(true).setCacheMode(
					CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
			int count = 0;
			while (results.next()) {
				writer.write(results.get(0));
				if (++count % batchSize == 0) {
					// release memory
//					session.flush();
					session.clear();
				}
			}

			fos.write("</ArrayList>".getBytes());
			fos.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	public class NoopOutputStream extends OutputStream {

		@Override
		public void write(int arg0) throws IOException {
		}
	}
	
	protected void multipleFiles(EntityManager em) {
		System.out.println("multipleFiles");
		// http://www.hibernate.org/hib_docs/v3/reference/en/html/batch.html
		Session session = HibernateUtil.getSession(em);
		ScrollableResults results = session.createQuery(eql).setCacheMode(
				CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
		int count = 0;
		while (results.next()) {
			export(results.get(0));
			if (++count % 20 == 0) {
				// flush a batch of updates and release memory:
				session.flush();
				session.clear();
			}
		}
	}

	protected void export(Object result) {
		try {
			FileOutputStream fos = new FileOutputStream(getFileName());
			BetwixtUtil.exportXml(result, fos, new EmptySuppressionStrategy(suppressions));
			fos.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
